﻿// --------------------------------------------------------------------------------------------------------------------
// <summary>
//   FileXmlInjectValuesStep.cs
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace TRlib.BizUnit.CustomSteps
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Xml;
    using global::BizUnit;

    /// <summary>
    /// The FileXmlInjectValuesStep reads a FILE from a given locaton sets values at given locations.
    /// </summary>
    /// 
    /// <remarks>
    /// The following shows an example of the Xml representation of this test step.
    /// 
    /// <code escaped="true">
    ///    <TestStep assemblyPath="" typeName="XPathFileValidationStep">
    ///        <FilePath>C:\temp\blah.xml</FilePath>
    ///        <XPathList>
    ///            <SetValueAt query="/*[local-name()='PurchaseOrder' and namespace-uri()='http://SendMail.PurchaseOrder']/*[local-name()='PONumber' and namespace-uri()='']">PONumber_0</XPathValidation>
    ///            <SetValueAt query="/*[local-name()='PurchaseOrder' and namespace-uri()='http://SendMail.PurchaseOrder']/*[local-name()='OtherField' and namespace-uri()='']" takeFromCtx="PONum" />
    ///        </XPathList>
    ///                    
    ///    </TestStep>
    ///    </code>
    ///    
    ///    <list type="table">
    ///        <listheader>
    ///            <term>Tag</term>
    ///            <description>Description</description>
    ///        </listheader>
    ///        <item>
    ///            <term>FilePath</term>
    ///            <description>XML file to modify</description>
    ///        </item>
    ///        <item>
    ///            <term>XPathList</term>
    ///            <description>Container for one or more &lt;SetValueAt&gt; tags</description>
    ///        </item>
    ///        <item>
    ///            <term>SetValueAt</term>
    ///            <description>Specifies a query and a value to inject at query. The value is optional if using @takeFromCtx (see below)</description>
    ///        </item>
    ///        <item>
    ///            <term>XPathValidation/@query</term>
    ///            <description>Required. An xpath expresion</description>
    ///        </item>
    ///        <item>
    ///            <term>XPathValidation/@takeFromCtx</term>
    ///            <description>Optional. Allows you to specify the expected value from the context by supplying a context key</description>
    ///        </item>
    ///    </list>
    /// </remarks>
    public class FileXmlInjectValuesStep : ITestStep
    {
        #region ITestStep Members

        public void Execute(XmlNode testConfig, Context context)
        {
            string file = context.ReadConfigAsString(testConfig, "FilePath");

            var doc = new XmlDocument();
            doc.Load(file);

            context.LogInfo(String.Format("Loaded file: {0}", file));
            var xpathChecks = testConfig.SelectNodes("//XPathList/*");

            this.ReplaceAllBySpecifiedXPaths(xpathChecks, context, doc);

            doc.Save(file);
        }

        #endregion

        private void ReplaceAllBySpecifiedXPaths(XmlNodeList checks, Context context, XmlDocument doc)
        {
            foreach (XmlNode xpathCheck in checks)
            {
                // Get xpath query
                var xpathExp = xpathCheck.SelectSingleNode("@query").Value;

                // Get value to be replaced
                var replaceThis = doc.SelectSingleNode(xpathExp).InnerText;

                // Get expected value
                string replaceWith;
                if (xpathCheck.Attributes["takeFromCtx"] != null) 
                {
                    // Implement takeFromCtx
                    string ctxValue = xpathCheck.Attributes["takeFromCtx"].Value;
                    replaceWith = context.GetValue(ctxValue);
                }
                else
                {
                    replaceWith = xpathCheck.SelectSingleNode(".").InnerText;
                }

                // Set the value at the xpath expression site.
                doc.SelectSingleNode(xpathExp).InnerText = replaceWith;

                context.LogInfo("Replaced {0} with {1} at XPath {2}", replaceThis, replaceWith, xpathExp);
            }
        }
    }
}
